package com.zihan.demo;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;


/**
 * C/S架构的服务端对象。
 *
 * <p>
 * <p>
 * 创建时间：2010-7-18 上午12:17:37
 *
 * @author HouLei
 * @since 1.0
 */

public class Server {
    private int port;
    private volatile boolean running = false;
    private long receiveTimeDelay = 3000;//接收时间间隔
    private ConcurrentHashMap<Class, ObjectAction> actionMapping = new ConcurrentHashMap<Class, ObjectAction>();
    private Thread connWatchDog;

    /**
     * 要处理客户端发来的对象，并返回一个对象，可实现该接口。
     */

    public interface ObjectAction {
        Object doAction(Object rev);
    }


    public static final class DefaultObjectAction implements ObjectAction {
        public Object doAction(Object rev) {
            System.out.println("处理并返回：" + rev);
            return rev;
        }
    }


    public static void main(String[] args) {
        int port = 65432;
        Server server = new Server(port);
        server.start();
    }

    public Server(int port) {
        this.port = port;
    }


    public void start() {
        if (running) {
            return;
        }
        running = true;
        connWatchDog = new Thread(new ConnWatchDog());
        connWatchDog.start();
    }


    @SuppressWarnings("deprecation")

    public void stop() {

        if (running) {
            running = false;
        }

        if (connWatchDog != null) {
            connWatchDog.stop();
        }

    }


    public void addActionMap(Class<Object> cls, ObjectAction action) {
        actionMapping.put(cls, action);
    }


    class ConnWatchDog implements Runnable {
        public void run() {
            try {
                ServerSocket ss = new ServerSocket(port, 5);
                while (running) {
                    Socket s = ss.accept();
                    new Thread(new SocketAction(s)).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
                Server.this.stop();
            }
        }
    }

    /**
     * 独立线程处理业务与控制连接
     */
    class SocketAction implements Runnable {
        Socket socket;
        boolean run = true;
        long lastReceiveTime = System.currentTimeMillis();
        public SocketAction(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            while (running && run) {
                if (System.currentTimeMillis() - lastReceiveTime > receiveTimeDelay) {
                    overThis();
                } else {
                    try {
                        InputStream in = socket.getInputStream();
                        if (in.available() > 0) {
                            ObjectInputStream ois = new ObjectInputStream(in);
                            Object obj = ois.readObject();
                            lastReceiveTime = System.currentTimeMillis();

                            System.out.println("接收：\t" + obj);

                            ObjectAction oa = actionMapping.get(obj.getClass());
                            oa = oa == null ? new DefaultObjectAction() : oa;

                            Object out = oa.doAction(obj);

                            if (out != null) {
                                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                                oos.writeObject(out);
                                oos.flush();
                            }
                        } else {
                            Thread.sleep(10);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        overThis();
                    }

                }

            }

        }

        /**
         * 关闭连接
         */
        private void overThis() {
            if (run) {
                run = false;
            }

            if (socket != null) {
                try {
                    socket.close();
                    System.out.println("关闭：" + socket.getRemoteSocketAddress());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}